package com.dieusoft.box.bill.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.dieusoft.box.bill.entity.InvoiceInfo;
import com.dieusoft.box.bill.entity.PayApplyInfo;
import com.dieusoft.box.bill.entity.WriteOffInfo;
import com.dieusoft.box.bill.entity.WriteOffRecordList;
import com.dieusoft.box.bill.service.IInvoiceService;
import com.dieusoft.box.bill.service.IPayApplyService;
import com.dieusoft.box.bill.service.IWriteOffHisRecordService;
import com.dieusoft.box.bill.service.IWriteOffService;
import com.dieusoft.box.bill.vo.WriteOffQueryVO;
import com.dieusoft.box.trade.entity.CostInfo;
import com.dieusoft.box.trade.service.ICostInfoService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.transaction.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * @Description: 费用核销
 * @Author: dongw
 * @Date: 2021-03-22
 * @Version: V1.0
 */
@Api(tags = "费用核销")
@RestController
@RequestMapping("/writeoff")
@Slf4j
public class WriteOffController {

    @Autowired
    private IInvoiceService invoiceService;

    @Autowired
    private IPayApplyService payApplyService;

    @Autowired
    private IWriteOffService writeOffService;

    @Autowired
    private ICostInfoService costInfoService;

    @Autowired
    private IWriteOffHisRecordService writeOffHisRecordService;


    @GetMapping("/query/bill/list")
    public Result queryBillList(@RequestParam(name = "payType") Integer payType, String billNumber, String settlementCompany) {
        if (payType == 1) {
            QueryWrapper<InvoiceInfo> invoiceInfoQueryWrapper = new QueryWrapper<>();
            invoiceInfoQueryWrapper.eq("status", 4);
            if (StringUtils.isNotBlank(billNumber)) {
                invoiceInfoQueryWrapper.like("invoice_serial", billNumber);
            }
            if (StringUtils.isNotBlank(settlementCompany)) {
                invoiceInfoQueryWrapper.like("settlement_company", settlementCompany);
            }
            List<InvoiceInfo> list = invoiceService.list(invoiceInfoQueryWrapper);
            List<WriteOffQueryVO> writeOffQueryVOS = convertData(1, null, list);
            return Result.OK(writeOffQueryVOS);
        } else if (payType == 2) {
            QueryWrapper<PayApplyInfo> payApplyInfoQueryWrapper = new QueryWrapper<>();
            payApplyInfoQueryWrapper.eq("status", 2);
            if (StringUtils.isNotBlank(billNumber)) {
                payApplyInfoQueryWrapper.like("pay_serial", billNumber);
            }
            if (StringUtils.isNotBlank(settlementCompany)) {
                payApplyInfoQueryWrapper.like("settlement_company", settlementCompany);
            }
            List<PayApplyInfo> list = payApplyService.list(payApplyInfoQueryWrapper);
            List<WriteOffQueryVO> writeOffQueryVOS = convertData(2, list, null);
            return Result.OK(writeOffQueryVOS);
        }
        return Result.OK(Collections.EMPTY_LIST);
    }


    /**
     * 保存/编辑
     *
     * @param actionType
     * @param writeOffInfo
     * @return
     */
    @PostMapping(value = "/action/{actionType}")
    @Transactional(rollbackOn = Exception.class)
    public Result save(@PathVariable String actionType, @RequestBody WriteOffInfo writeOffInfo) {
        if ("save".equals(actionType)) {
            List<String> billIds = Arrays.asList(writeOffInfo.getBillIds().split(","));
            if ("1".equals(writeOffInfo.getPayType())) {//应收
                UpdateWrapper<InvoiceInfo> invoiceInfoUpdateWrapper = new UpdateWrapper<>();
                BigDecimal actualAmount = new BigDecimal(writeOffInfo.getActualAmount());
                BigDecimal writeoffRate = new BigDecimal(writeOffInfo.getWriteoffRate());
                //实际核销
                BigDecimal actualCnyAmount = actualAmount.multiply(writeoffRate);
                //应核销
                BigDecimal writeoffAmount = new BigDecimal(writeOffInfo.getWriteoffAmount());

                //判断实际核销金额CNY和单据总金额是否相等
                //相等为全部核销
                int statusFlag = 5;
                if (actualCnyAmount.compareTo(writeoffAmount) == 0) {
                    invoiceInfoUpdateWrapper.set("status", 5);//状态改为全部结算
                } else if (actualCnyAmount.compareTo(writeoffAmount) == 1) {
                    return Result.error("实销金额大于所选单据总金额，核销失败");
                } else {
                    statusFlag = 6;
                    writeOffInfo.setStatus(2);//部分核销
                    invoiceInfoUpdateWrapper.set("status", 6);//状态改为部分结算
                }

                invoiceInfoUpdateWrapper.in("id", billIds);
                invoiceService.update(invoiceInfoUpdateWrapper);
                //更新单据的状态
                QueryWrapper<InvoiceInfo> invoiceInfoQueryWrapper = new QueryWrapper<>();
                invoiceInfoQueryWrapper.in("id", billIds);
                //更新费用的状态
                List<InvoiceInfo> invoiceInfoList = invoiceService.list(invoiceInfoQueryWrapper);
                UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
                costInfoUpdateWrapper.set("s_code", statusFlag + 1);
                costInfoUpdateWrapper.set("status", statusFlag == 5 ? "核销完成" : "部分核销");
                invoiceInfoList.stream().forEach(item -> {
                    costInfoUpdateWrapper.in("id", Arrays.asList(item.getCostIds().split(",")));
                    costInfoService.update(costInfoUpdateWrapper);
                });
                //应付
            } else if ("2".equals(writeOffInfo.getPayType())) {
                UpdateWrapper<PayApplyInfo> payApplyInfoUpdateWrapper = new UpdateWrapper<>();
                BigDecimal actualAmount = new BigDecimal(writeOffInfo.getActualAmount());
                BigDecimal writeoffRate = new BigDecimal(writeOffInfo.getWriteoffRate());
                //实际核销
                BigDecimal actualCnyAmount = actualAmount.multiply(writeoffRate);
                //应核销
                BigDecimal writeoffAmount = new BigDecimal(writeOffInfo.getWriteoffAmount());

                //判断实际核销金额CNY和单据总金额是否相等
                //相等为全部核销
                int statusFlag = 5;
                if (actualCnyAmount.compareTo(writeoffAmount) == 0) {
                    payApplyInfoUpdateWrapper.set("status", 4);//状态改为全部结算
                } else if (actualCnyAmount.compareTo(writeoffAmount) == 1) {
                    return Result.error("实销金额大于所选单据总金额，核销失败");
                } else {
                    statusFlag = 6;
                    writeOffInfo.setStatus(2);//部分核销
                    payApplyInfoUpdateWrapper.set("status", 5);//状态改为部分结算
                }

                payApplyInfoUpdateWrapper.in("id", billIds);
                payApplyService.update(payApplyInfoUpdateWrapper);
                //更新单据的状态
                QueryWrapper<PayApplyInfo> payApplyInfoQueryWrapper = new QueryWrapper<>();
                payApplyInfoQueryWrapper.in("id", billIds);
                //更新费用的状态
                List<PayApplyInfo> payApplyInfoList = payApplyService.list(payApplyInfoQueryWrapper);
                UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
                costInfoUpdateWrapper.set("s_code", statusFlag + 1);
                costInfoUpdateWrapper.set("status", statusFlag == 5 ? "核销完成" : "部分核销");
                payApplyInfoList.stream().forEach(item -> {
                    costInfoUpdateWrapper.in("id", Arrays.asList(item.getCostIds().split(",")));
                    costInfoService.update(costInfoUpdateWrapper);
                });
            }
            writeOffInfo.setWriteoffSerial(getPayNumber());
            writeOffService.save(writeOffInfo);
            //写入核销记录信息
            WriteOffRecordList writeOffRecordList = new WriteOffRecordList();
            writeOffRecordList.setBuisId(writeOffInfo.getId());
            StringBuffer content = new StringBuffer();
            content.append("1".equals(writeOffInfo.getPayType()) ? "收款，" : "付款，");
            content.append("单据总金额(CNY):").append(writeOffInfo.getWriteoffAmount()).append("，");
            BigDecimal actualCny = new BigDecimal(writeOffInfo.getActualAmount()).multiply(new BigDecimal(writeOffInfo.getWriteoffRate()));
            content.append("本次实销:").append(writeOffInfo.getActualAmount() + "/CNY:" + actualCny).append("，");
            content.append("汇率：").append(writeOffInfo.getWriteoffRate()).append("，");
            content.append("核销币种：").append(writeOffInfo.getWriteoffCurrency()).append(",");
            content.append("结算方式：").append(writeOffInfo.getSettlementType()).append(",");
            content.append("剩余未核销金额(CNY)：").append(new BigDecimal(writeOffInfo.getWriteoffAmount()).subtract(actualCny)).append(",");
            writeOffRecordList.setContent(content.toString());
            writeOffRecordList.setWriteoffDate(writeOffInfo.getWriteoffDate());
            writeOffHisRecordService.save(writeOffRecordList);
        }
        return Result.OK().success("操作成功");
    }

    /**
     * 列表查询
     *
     * @param payType
     * @param writeoffSerial
     * @param settlementCompany
     * @param createBy
     * @param status
     * @param pageNo
     * @param pageSize
     * @return
     */
    @GetMapping("/list")
    public Result queryBillList(Integer payType, String writeoffSerial, String settlementCompany, String createBy, Integer status,
                                @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
                                @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize) {
        QueryWrapper<WriteOffInfo> writeOffInfoQueryWrapper = new QueryWrapper<>();

        if (null != payType) {
            writeOffInfoQueryWrapper.eq("pay_type", payType);
        }
        if (null != status) {
            writeOffInfoQueryWrapper.eq("status", status);
        }
        if (StringUtils.isNotBlank(writeoffSerial)) {
            writeOffInfoQueryWrapper.like("writeoff_serial", writeoffSerial);
        }
        if (StringUtils.isNotBlank(settlementCompany)) {
            writeOffInfoQueryWrapper.like("settlement_company", settlementCompany);
        }
        if (StringUtils.isNotBlank(createBy)) {
            writeOffInfoQueryWrapper.like("create_by", createBy);
        }

        Page<WriteOffInfo> page = new Page<WriteOffInfo>(pageNo, pageSize);
        IPage<WriteOffInfo> pageList = writeOffService.page(page, writeOffInfoQueryWrapper);
        return Result.OK(pageList);
    }

    @GetMapping("/record/{id}")
    public Result queryHisRecordList(@PathVariable String id) {
        QueryWrapper<WriteOffRecordList> writeOffRecordListQueryWrapper = new QueryWrapper<>();
        writeOffRecordListQueryWrapper.eq("buis_id", id);
        List<WriteOffRecordList> list = writeOffHisRecordService.list(writeOffRecordListQueryWrapper);
        return Result.OK(list);
    }

    /**
     * 继续核销
     *
     * @param writeOffInfo
     * @return
     */
    @PostMapping("/continue")
    @Transactional(rollbackOn = Exception.class)
    public Result continueWriteOff(@RequestBody WriteOffInfo writeOffInfo) {
        if (StringUtils.isNotBlank(writeOffInfo.getId())) {
            WriteOffInfo offInfo = writeOffService.getById(writeOffInfo.getId());
            BigDecimal offInfoActualAmount = new BigDecimal((offInfo.getActualAmount()));
            BigDecimal offInfoAmount = new BigDecimal((offInfo.getWriteoffAmount()));
            BigDecimal offInfoRate = new BigDecimal((offInfo.getWriteoffRate()));
            BigDecimal thisOffInfoRate = new BigDecimal((writeOffInfo.getWriteoffRate()));
            BigDecimal thisOffInfoActualAmount = new BigDecimal((writeOffInfo.getActualAmount()));
            //本次实际核销CNY
            BigDecimal thisActualCNY = thisOffInfoRate.multiply(thisOffInfoActualAmount);
            //之前核销的CNY
            BigDecimal hisActualCNY = offInfoActualAmount.multiply(offInfoRate);

            //一共核销的CNY
            BigDecimal totalActualCNY = thisActualCNY.add(hisActualCNY);
            //核销完成
            //TODO 此处判断单据总金额和所有历史核销的总金额是否一致
            if (offInfoAmount.compareTo(totalActualCNY) == 0) {
                offInfo.setStatus(1);
                List<String> listBillIds = Arrays.asList(offInfo.getBillIds().split(","));
                if ("1".equals(offInfo.getPayType())) {
                    UpdateWrapper<InvoiceInfo> invoiceInfoUpdateWrapper = new UpdateWrapper<>();
                    invoiceInfoUpdateWrapper.set("status", 5);
                    invoiceInfoUpdateWrapper.in("id", listBillIds);
                    invoiceService.update(invoiceInfoUpdateWrapper);
                    //更新单据的状态
                    QueryWrapper<InvoiceInfo> invoiceInfoQueryWrapper = new QueryWrapper<>();
                    invoiceInfoQueryWrapper.in("id", listBillIds);
                    //更新费用的状态
                    List<InvoiceInfo> invoiceInfoList = invoiceService.list(invoiceInfoQueryWrapper);
                    UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
                    costInfoUpdateWrapper.set("s_code", 6);
                    costInfoUpdateWrapper.set("status", "核销完成");
                    invoiceInfoList.stream().forEach(item -> {
                        costInfoUpdateWrapper.in("id", Arrays.asList(item.getCostIds().split(",")));
                        costInfoService.update(costInfoUpdateWrapper);
                    });
                } else if ("2".equals(offInfo.getPayType())) {
                    UpdateWrapper<PayApplyInfo> payApplyInfoUpdateWrapper = new UpdateWrapper<>();
                    payApplyInfoUpdateWrapper.set("status", 4);
                    payApplyInfoUpdateWrapper.in("id", listBillIds);
                    payApplyService.update(payApplyInfoUpdateWrapper);
                    //更新单据的状态
                    QueryWrapper<PayApplyInfo> payApplyInfoQueryWrapper = new QueryWrapper<>();
                    payApplyInfoQueryWrapper.in("id", listBillIds);
                    //更新费用的状态
                    List<PayApplyInfo> payApplyInfoList = payApplyService.list(payApplyInfoQueryWrapper);
                    UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
                    costInfoUpdateWrapper.set("s_code", 6);
                    costInfoUpdateWrapper.set("status", "核销完成");
                    payApplyInfoList.stream().forEach(item -> {
                        costInfoUpdateWrapper.in("id", Arrays.asList(item.getCostIds().split(",")));
                        costInfoService.update(costInfoUpdateWrapper);
                    });
                }
            } else if (offInfoAmount.compareTo(totalActualCNY) == -1) {
                return Result.error("核销金额大于单据总金额");
            }
            offInfo.setActualAmount(offInfoActualAmount.add(thisActualCNY).toString());
            writeOffService.updateById(offInfo);
            //写入核销记录信息
            WriteOffRecordList writeOffRecordList = new WriteOffRecordList();
            writeOffRecordList.setBuisId(offInfo.getId());
            StringBuffer content = new StringBuffer();
            content.append("1".equals(offInfo.getPayType()) ? "收款，" : "付款，");
            content.append("单据总金额(CNY):").append(writeOffInfo.getWriteoffAmount()).append("，");
            content.append("本次实销:").append(writeOffInfo.getActualAmount() + "/CNY:" + thisActualCNY).append("，");
            content.append("汇率：").append(writeOffInfo.getWriteoffRate()).append("，");
            content.append("核销币种：").append(writeOffInfo.getWriteoffCurrency()).append(",");
            content.append("结算方式：").append(writeOffInfo.getSettlementType()).append(",");
            content.append("剩余未核销金额(CNY)：").append(new BigDecimal(writeOffInfo.getWriteoffAmount()).subtract(thisActualCNY)).append(",");
            writeOffRecordList.setContent(content.toString());
            writeOffRecordList.setWriteoffDate(offInfo.getWriteoffDate());
            writeOffHisRecordService.save(writeOffRecordList);
            return Result.OK().success("核销操作完成");
        } else {
            return Result.error("核销单据不存在");
        }
    }

    /**
     * 取消核销
     *
     * @param id
     * @return
     */
    @DeleteMapping("/cancel/{id}")
    public Result delWriteOff(@PathVariable String id) {
        WriteOffInfo writeOffInfo = writeOffService.getById(id);
        List<String> billIds = Arrays.asList(writeOffInfo.getBillIds().split(","));
        if ("1".equals(writeOffInfo.getPayType())) {//应收
            UpdateWrapper<InvoiceInfo> invoiceInfoUpdateWrapper = new UpdateWrapper<>();
            invoiceInfoUpdateWrapper.set("status", 4);
            invoiceInfoUpdateWrapper.in("id", billIds);
            invoiceService.update(invoiceInfoUpdateWrapper);
            //更新单据的状态
            QueryWrapper<InvoiceInfo> invoiceInfoQueryWrapper = new QueryWrapper<>();
            invoiceInfoQueryWrapper.in("id", billIds);
            //更新费用的状态
            List<InvoiceInfo> invoiceInfoList = invoiceService.list(invoiceInfoQueryWrapper);
            UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
            costInfoUpdateWrapper.set("s_code", 5);
            costInfoUpdateWrapper.set("status", "已开票");
            invoiceInfoList.stream().forEach(item -> {
                costInfoUpdateWrapper.in("id", Arrays.asList(item.getCostIds().split(",")));
                costInfoService.update(costInfoUpdateWrapper);
            });
            //应付
        } else if ("2".equals(writeOffInfo.getPayType())) {
            UpdateWrapper<PayApplyInfo> payApplyInfoUpdateWrapper = new UpdateWrapper<>();
            payApplyInfoUpdateWrapper.set("status", 2);
            payApplyInfoUpdateWrapper.in("id", billIds);
            payApplyService.update(payApplyInfoUpdateWrapper);
            //更新单据的状态
            QueryWrapper<PayApplyInfo> payApplyInfoQueryWrapper = new QueryWrapper<>();
            payApplyInfoQueryWrapper.in("id", billIds);
            //更新费用的状态
            List<PayApplyInfo> payApplyInfoList = payApplyService.list(payApplyInfoQueryWrapper);
            UpdateWrapper<CostInfo> costInfoUpdateWrapper = new UpdateWrapper<>();
            costInfoUpdateWrapper.set("s_code", 5);
            costInfoUpdateWrapper.set("status", "结算中");
            payApplyInfoList.stream().forEach(item -> {
                costInfoUpdateWrapper.in("id", Arrays.asList(item.getCostIds().split(",")));
                costInfoService.update(costInfoUpdateWrapper);
            });
        }
        boolean b = writeOffService.removeById(id);
        return b ? Result.OK().success("核销信息已删除") : Result.error("核销信息取消失败");


    }

    @GetMapping("/query/bill")
    public Result queryBillList(@RequestParam(name = "payType") Integer payType, @RequestParam(name = "billIds") String billIds) {

        if (payType == 1) {
            QueryWrapper<InvoiceInfo> invoiceInfoQueryWrapper = new QueryWrapper<>();
            invoiceInfoQueryWrapper.in("id", Arrays.asList(billIds.split(",")));
            List<InvoiceInfo> invoiceInfoList = invoiceService.list(invoiceInfoQueryWrapper);
            List<WriteOffQueryVO> writeOffQueryVOS = convertData(1, null, invoiceInfoList);
            return Result.OK(writeOffQueryVOS);
        } else if (payType == 2) {
            QueryWrapper<PayApplyInfo> payApplyInfoQueryWrapper = new QueryWrapper<>();
            payApplyInfoQueryWrapper.in("id", Arrays.asList(billIds.split(",")));
            List<PayApplyInfo> payApplyInfoList = payApplyService.list(payApplyInfoQueryWrapper);
            List<WriteOffQueryVO> writeOffQueryVOS = convertData(2, payApplyInfoList, null);
            return Result.OK(writeOffQueryVOS);
        }
        return Result.OK(Collections.EMPTY_LIST);
    }

    private List<WriteOffQueryVO> convertData(int type, List<PayApplyInfo> payApplyInfoList, List<InvoiceInfo> invoiceInfoList) {
        List<WriteOffQueryVO> writeOffQueryVOList = new ArrayList<>();
        if (type == 1) {
            invoiceInfoList.stream().forEach(item -> {
                WriteOffQueryVO writeOffQueryVO = new WriteOffQueryVO();
                writeOffQueryVO.setId(item.getId());
                writeOffQueryVO.setSettlementCompany(item.getSettlementCompany());
                writeOffQueryVO.setCheckUser(item.getCheckUser());
                writeOffQueryVO.setSerial(item.getInvoiceSerial());
                writeOffQueryVO.setCnyAmount(item.getCnyAmount());
                writeOffQueryVO.setRate(item.getRate());
                writeOffQueryVO.setCurrency(item.getCurrency());
                writeOffQueryVO.setCheckUser(item.getCheckUser());
                writeOffQueryVO.setCheckDate(item.getCheckDate());
                writeOffQueryVO.setCreateTime(item.getCreateTime());
                writeOffQueryVO.setCreateBy(item.getCreateBy());
                writeOffQueryVO.setRemark(item.getRemark());
                writeOffQueryVO.setAmount(item.getAmount());
                String status = "审核完成";
                if (item.getStatus() == 5) {
                    status = "核销完成";
                } else if (item.getStatus() == 6) {
                    status = "部分核销";
                }
                writeOffQueryVO.setStatus(status);
                writeOffQueryVOList.add(writeOffQueryVO);
            });
        } else if (type == 2) {
            payApplyInfoList.stream().forEach(item -> {
                WriteOffQueryVO writeOffQueryVO = new WriteOffQueryVO();
                writeOffQueryVO.setId(item.getId());
                writeOffQueryVO.setSettlementCompany(item.getSettlementCompany());
                writeOffQueryVO.setCheckUser(item.getCheckUser());
                writeOffQueryVO.setSerial(item.getPaySerial());
                writeOffQueryVO.setCnyAmount(item.getCnyAmount());
                writeOffQueryVO.setRate(item.getRate());
                writeOffQueryVO.setCurrency(item.getCurrency());
                writeOffQueryVO.setCheckUser(item.getCheckUser());
                writeOffQueryVO.setCheckDate(item.getCheckDate());
                writeOffQueryVO.setCreateTime(item.getCreateTime());
                writeOffQueryVO.setCreateBy(item.getCreateBy());
                writeOffQueryVO.setRemark(item.getRemark());
                writeOffQueryVO.setAmount(item.getAmount());
                String status = "审核完成";
                if (item.getStatus() == 4) {
                    status = "核销完成";
                } else if (item.getStatus() == 5) {
                    status = "部分核销";
                }
                writeOffQueryVO.setStatus(status);
                writeOffQueryVOList.add(writeOffQueryVO);
            });
        }
        return writeOffQueryVOList;
    }

    /**
     * 生成发票流水号
     *
     * @return
     */
    private synchronized String getPayNumber() {
        StringBuffer sb = new StringBuffer().append("HX");
        String yymmdd = DateTimeFormatter.ofPattern("yyMMdd").format(LocalDate.now());
        sb.append(yymmdd);
        String s = sb.toString();
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.like("writeoff_serial", s);
        int count = writeOffService.count(queryWrapper);
        String billNumber = String.format("%0" + 4 + "d", count + 1);
        return sb.append(billNumber).toString();
    }

}
